package org.cqust.backend.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.cqust.backend.common.ApiResult;
import org.cqust.backend.controller.base.BaseController;
import org.cqust.backend.dto.request.mission.attempt.MissionAttemptRequestDTO;
import org.cqust.backend.dto.request.mission.attempt.MissionStepAttemptRequestDTO;
import org.cqust.backend.dto.request.mission.MissionCreateRequestDTO;
import org.cqust.backend.dto.request.mission.MissionUpdateRequestDTO;
import org.cqust.backend.dto.request.mission.StepCreateRequestDTO;
import org.cqust.backend.dto.request.mission.StepUpdateRequestDTO;
import org.cqust.backend.dto.response.mission.attempt.MissionAttemptCreateDTO;
import org.cqust.backend.dto.response.mission.attempt.MissionAttemptDTO;
import org.cqust.backend.dto.response.mission.MissionCreateDTO;
import org.cqust.backend.dto.response.mission.MissionDTO;
import org.cqust.backend.dto.response.mission.StepVersionDTO;
import org.cqust.backend.dto.response.mission.attempt.MissionStepAttemptDTO;
import org.cqust.backend.entity.User;
import org.cqust.backend.entity.mission.attempt.MissionStepAttempt;
import org.cqust.backend.service.mission.MissionAttemptService;
import org.cqust.backend.service.mission.MissionService;
import org.cqust.backend.service.mission.MissionStepService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.List;
@RestController
@RequestMapping("/api/mission")
@Tag(name = "Mission Controller", description = "API endpoints for managing missions and attempts")
public class MissionController extends BaseController {
    private final MissionService missionService;
    private final MissionStepService missionStepService;
    private final MissionAttemptService missionAttemptService;

    public MissionController(MissionService missionService, MissionStepService missionStepService, MissionAttemptService missionAttemptService) {
        this.missionService = missionService;
        this.missionStepService = missionStepService;
        this.missionAttemptService = missionAttemptService;
    }

    /**
     * 获取所有可用任务
     * @return ApiResult 包含所有可用任务的列表
     */
    @Operation(summary = "获取所有可用任务", description = "返回所有可用任务的列表")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取任务列表"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @GetMapping
    @PreAuthorize("permitAll()")
    public ApiResult<List<MissionDTO>> getAllMissions() {
        List<MissionDTO> availableMissions = missionService.getAvailableMissions();
        // 如果用户是教师，则返回所有任务；否则仅返回已发布的任务
        if(hasAuthority("Teacher")) {
            return ApiResult.success(availableMissions);
        }else{
            return ApiResult.success(availableMissions.stream().filter(MissionDTO::getPublished).toList());
        }
    }

    @Operation(summary = "获取单个任务", description = "根据任务ID返回单个任务的详细信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取任务"),
            @ApiResponse(responseCode = "400", description = "任务未找到",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @GetMapping("/{missionId}")
    @PreAuthorize("permitAll()")
    public ApiResult<MissionDTO> getMission(@Parameter(description = "任务ID", required = true) @PathVariable Long missionId) {
        MissionDTO mission = missionService.getMissionById(missionId);
        // 如果任务未发布，则仅允许教师获取
        if(!mission.getPublished()){
            if(!hasAuthority("Teacher"))
                return ApiResult.error("无权获取此任务");
        }
        return ApiResult.success(mission);
    }


    /**
     * 获取任务的详细步骤列表
     * @param missionId 任务ID
     * @return ApiResult 包含任务详细步骤列表
     */
    @Operation(summary = "获取任务的详细步骤列表", description = "根据任务ID返回任务的详细步骤列表")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取步骤列表"),
            @ApiResponse(responseCode = "400", description = "任务未找到",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @GetMapping("/{missionId}/steps")
    @PreAuthorize("permitAll()")
    public ApiResult<List<StepVersionDTO>> getMissionSteps(@Parameter(description = "任务ID", required = true) @PathVariable Long missionId) {
        return ApiResult.success(missionStepService.getLatestStepsByMissionId(missionId));
    }

    /**
     * 获取用户的所有实验记录（需要登录）
     * @return ApiResult 包含用户的所有实验记录
     */
    @Operation(summary = "获取用户的所有实验记录", description = "返回当前登录用户的所有实验记录，如果是教师，则返回所有实验记录")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取实验记录"),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @GetMapping("/attempts")
    @PreAuthorize("isAuthenticated()")
    public ApiResult<List<MissionAttemptDTO>> getUserAttempts() {
        if(isTeacher()){
            return ApiResult.success(missionService.getAllMissionAttempts());
        }
        Long userId = getCurrentUserId();
        return ApiResult.success(missionService.getMissionAttemptsByUserId(userId));
    }

    @GetMapping("/stepAttempts/{missionAttemptId}")
    public ApiResult<List<MissionStepAttemptDTO>> getStepAttempts(
            @Parameter(description = "任务尝试ID", required = true) @PathVariable Long missionAttemptId
    ){
        return ApiResult.success(missionService.getAllMissionStepAttempts(missionAttemptId));
    }


    /**
     * 更新任务的某个步骤（带版本控制，确保存在用户记录时，数据不会被更改）
     * @param stepDTO 步骤更新请求DTO
     * @return ApiResult 更新结果
     */
    @Operation(summary = "更新任务的某个步骤", description = "更新任务的某个步骤，带版本控制")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功更新步骤"),
            @ApiResponse(responseCode = "400", description = "无效请求",
                    content = @Content),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @PostMapping("/updateStep")
    @PreAuthorize("hasAuthority('Teacher')")
    public ApiResult<String> updateStep(
            @Parameter(description = "步骤更新请求DTO", required = true) @RequestBody StepUpdateRequestDTO stepDTO) {
        missionStepService.updateStepWithVersionControl(stepDTO);
        return ApiResult.success();
    }

    /**
     * 更新任务（带版本控制，确保存在用户记录时，旧数据不会被更改）
     * @param updateRequestDTO 任务更新请求DTO
     * @return ApiResult 更新结果
     */
    @Operation(summary = "更新任务", description = "更新任务，带版本控制")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功更新任务"),
            @ApiResponse(responseCode = "400", description = "无效请求",
                    content = @Content),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @PostMapping("/updateMission")
    @PreAuthorize("hasAuthority('Teacher')")
    public ApiResult<String> updateMission(
            @Parameter(description = "任务更新请求DTO", required = true) @RequestBody MissionUpdateRequestDTO updateRequestDTO) {
        missionService.updateMissionWithVersionControl(updateRequestDTO);
        return ApiResult.success();
    }

    /**
     * 添加新的步骤到任务中
     * @param stepRequest 步骤创建请求DTO
     * @return ApiResult 添加结果
     */
    @Operation(summary = "添加新的步骤到任务中", description = "向任务中添加新的步骤")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功添加步骤"),
            @ApiResponse(responseCode = "400", description = "无效请求",
                    content = @Content),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @PostMapping("/createStep")
    @PreAuthorize("hasAuthority('Teacher')")
    public ApiResult<String> addStepToMission(
            @Parameter(description = "步骤创建请求DTO", required = true) @RequestBody StepCreateRequestDTO stepRequest) {
        missionStepService.addStepToMission(stepRequest);
        return ApiResult.success();
    }

    /**
     * 创建新的任务
     * @param createRequestDTO 任务创建请求DTO
     * @return ApiResult 创建结果
     */
    @Operation(summary = "创建新的任务", description = "创建一个新的任务")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功创建任务"),
            @ApiResponse(responseCode = "400", description = "无效请求",
                    content = @Content),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @PostMapping("/create")
    @PreAuthorize("hasAuthority('Teacher')")
    public ApiResult<MissionCreateDTO> createMission(@Parameter(description = "任务创建请求DTO", required = true) @RequestBody MissionCreateRequestDTO createRequestDTO) {
        return ApiResult.success(missionService.createNewMission(createRequestDTO));
    }

    /**
     * 记录任务尝试
     * @param requestDTO 包含任务ID的DTO
     * @return ApiResult 记录结果
     */
    @Operation(summary = "记录任务尝试", description = "记录用户的任务尝试")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功记录任务尝试"),
            @ApiResponse(responseCode = "400", description = "无效请求",
                    content = @Content),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @PostMapping("/attempts/mission")
    @PreAuthorize("isAuthenticated()")
    public ApiResult<MissionAttemptCreateDTO> startMissionAttempt(
            @Parameter(description = "创建申请DTO", required = true) @RequestBody MissionAttemptRequestDTO requestDTO) {
        Long userId = getCurrentUserId();
        return ApiResult.success(missionAttemptService.createAttempt(requestDTO.getMissionId(), userId));
    }

    /**
     * 记录步骤尝试
     * @param attemptRequest 步骤尝试请求DTO
     * @return ApiResult 记录结果
     */
    @Operation(summary = "记录步骤尝试", description = "记录用户的步骤尝试")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功记录步骤尝试"),
            @ApiResponse(responseCode = "400", description = "无效请求",
                    content = @Content),
            @ApiResponse(responseCode = "401", description = "未授权",
                    content = @Content),
            @ApiResponse(responseCode = "500", description = "服务器内部错误",
                    content = @Content) })
    @PostMapping("/attempts/step")
    @PreAuthorize("isAuthenticated()")
    public ApiResult<String> recordStepAttempt(
            @Parameter(description = "步骤尝试请求DTO", required = true) @RequestBody MissionStepAttemptRequestDTO attemptRequest) {
        Long userId = getCurrentUserId();
        missionAttemptService.recordStepAttempt(attemptRequest, userId);
        return ApiResult.success();
    }
    private boolean isTeacher(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User user = (User) authentication.getPrincipal();
        return user.getRole().equals("Teacher");
    }
    private Long getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User user = (User) authentication.getPrincipal();
        return user.getId();
    }
}